package org.xserver.component.core.dispatch.http;


import java.lang.reflect.Method;
import java.util.List;

import javax.annotation.Resource;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.jboss.netty.handler.ssl.SslHandler;
import org.springframework.stereotype.Component;
import org.xserver.common.util.StringUtil;
import org.xserver.component.annotation.Path;
import org.xserver.component.core.XServerHttpContextAttachment;
import org.xserver.component.core.XServerHttpRequest;
import org.xserver.component.core.interfaces.InterfaceContext;
import org.xserver.component.core.interfaces.InterfaceMeta;
import org.xserver.component.exception.RequestTypeException;
import org.xserver.component.exception.ResouceNotFoundError;
import org.xserver.component.extension.filter.parameter.XServerParametersProcessFilter;
import org.xserver.component.handler.ext.WriteHandler;
import org.xserver.component.handler.ext.WriteHandlerFactory.ResponseType;
import org.xserver.component.prototype.annotation.ResponsePrototype;
import org.xserver.component.spring.SpringUtil;
import org.xserver.disruptor.core.DisruptorEventFactory;
import org.xserver.disruptor.producer.RequestEvent;
@Component
public class WebSocketRequestDispatch extends HttpRequestDispatch{
	@Resource
	private InterfaceContext interfaceContext;
	@Resource
	private DisruptorEventFactory disruptorEventFactory;
	@Override
	protected void doRequest(XServerHttpContextAttachment attachment,
			WriteHandler writeHandler) throws Exception {
		String path = attachment.getRequest().getPath();
		InterfaceMeta interfaceMeta = interfaceContext.getInterfaceMeta(path);
		if (interfaceMeta == null) {
			throw new ResouceNotFoundError(HttpResponseStatus.BAD_REQUEST,
					"PATH \'" + path + "\' CANNOT MATCH ANY INTERFACE.");
		}

		Method method = interfaceMeta.getMethod();
		requestTypeInvoke(attachment, method);
		Class<?> clazz = interfaceMeta.getClazz();
		Object httpInterface = SpringUtil.getBean(StringUtil
				.toLowerCaseAtIndex(clazz.getSimpleName(), 0));
		XServerHttpRequest request = attachment.getRequest();
		if (attachment.isWebsocket()) {
			Channel channel = attachment.getChannelHandlerContext()
					.getChannel();
			request.setChannel(channel);
		}

		@SuppressWarnings("unchecked")
		List<Object> objects = (List<Object>) (attachment.getAttachment())
				.get(XServerParametersProcessFilter.class.getSimpleName());
		Object[] parameters = objects.toArray(new Object[objects.size()]);
		
		disruptorEventFactory.post(RequestEvent.getInstance(method, httpInterface, parameters, writeHandler,attachment));
	}

	@Override
	public ResponseType getResponsePrototype(
			XServerHttpContextAttachment attachment) {
		String path = attachment.getRequest().getPath();

		InterfaceMeta interfaceMeta = interfaceContext.getInterfaceMeta(path);
		ResponseType responseType = ResponseType.HTTP;

		ResponsePrototype responsePrototype = interfaceMeta.getMethod()
				.getAnnotation(ResponsePrototype.class);
		if (responsePrototype != null) {
			responseType = responsePrototype.value();
		}

		return responseType;
	}

	@Override
	public boolean accept(XServerHttpContextAttachment attachment) {
		String path = attachment.getRequest().getPath();
		return interfaceContext.getInterfaceContext().containsKey(path);
	}

	/**
	 * Checking request protocol
	 * 
	 * @param attachment
	 * @param method
	 */
	private void requestTypeInvoke(XServerHttpContextAttachment attachment,
			Method method) {
		Path pathAnnotation = method.getAnnotation(Path.class);
		ChannelHandler sslChannelHandle = attachment.getChannelHandlerContext()
				.getPipeline().get(SslHandler.class.getSimpleName());

		switch (pathAnnotation.prototype()) {
		case HTTP:
			if (sslChannelHandle != null) {
				throw new RequestTypeException(
						RequestTypeException.RequestTypeExceptionEnum.NEED_HTTP);
			}
			break;
		case HTTPS:
			if (sslChannelHandle == null) {
				throw new RequestTypeException(
						RequestTypeException.RequestTypeExceptionEnum.NEED_HTTPS);
			}
			break;
		default:
			throw new RequestTypeException(
					RequestTypeException.RequestTypeExceptionEnum.NOT_SUPPORTED_PROTOTYPE);
		}
	}

}
